package com.chenfan.process.pattern.template;

import com.alibaba.fastjson.JSONObject;
import com.chenfan.ccp.common.exception.ApiException;
import com.chenfan.ccp.entity.BaseEntity;
import com.chenfan.ccp.util.tool.UuidUtil;
import com.chenfan.infra.context.UserContextHolder;
import com.chenfan.infra.vo.UserVO;
import com.chenfan.notify.MessageClient;
import com.chenfan.privilege.client.PrivilegeClient;
import com.chenfan.privilege.dto.UserDTO;
import com.chenfan.privilege.vo.DepartmentHeadVO;
import com.chenfan.process.biz.impl.EventPublisherBiz;
import com.chenfan.process.common.exception.ProcessResultCode;
import com.chenfan.process.context.ApprovalEventContext;
import com.chenfan.process.context.CounterSignContext;
import com.chenfan.process.dto.ApprovalCallBack;
import com.chenfan.process.dto.ApprovalDTO;
import com.chenfan.process.entity.dto.ApprovalUserDTO;
import com.chenfan.process.entity.dto.DetailAndProcessInstanceDTO;
import com.chenfan.process.entity.dto.InstanceSnapshotDTO;
import com.chenfan.process.entity.po.*;
import com.chenfan.process.enums.*;
import com.chenfan.process.event.callback.TriggerCallbackEventData;
import com.chenfan.process.service.*;
import com.chenfan.process.service.impl.ApprovalSnapshotDomainService;
import com.chenfan.process.util.*;
import groovy.lang.Tuple2;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;

import java.util.*;
import java.util.stream.Collectors;

/**
 * @author K
 * @date 2022/7/11 4:16 PM
 */
@Slf4j
public abstract class AbstractNodeHandler {

    @Autowired
    protected PrivilegeClient privilegeClient;
    @Autowired
    protected ProcessInstanceApproveService processInstanceApproveService;
    @Autowired
    protected ProcessDetailService processDetailService;
    @Autowired
    protected ProcessService processService;
    @Autowired
    protected EventPublisherBiz eventPublisherBiz;
    @Autowired
    protected ProcessRelatedService processRelatedService;
    @Autowired
    protected ProcessFormNodeRelationService processFormNodeRelationService;
    @Autowired
    protected ProcessRelatedAttributeService processRelatedAttributeService;
    @Autowired
    protected ApprovalService approvalService;
    @Autowired
    private ProcessCarbonCopyService carbonCopyService;
    @Autowired
    private ApprovalTemplateService approvalTemplateService;
    @Autowired
    private ProcessNodeNotifyConfigService processNodeNotifyConfigService;
    @Autowired
    private MessageClient messageClient;
    @Autowired
    protected ApprovalSnapshotDomainService approvalSnapshotDomainService;
    @Autowired
    protected ApprovalSnapshotPoService approvalSnapshotPoService;
    @Autowired
    protected TemplateConfigService templateConfigService;

    protected ApprovalPo approvalPo;
    protected List<ProcessRelatedPo> processRelatedPoList;
    protected ProcessDetailPo before;
    protected ApprovalDTO approvalDTO;
    protected DetailAndProcessInstanceDTO detailAndProcessInstance;

    protected String checkField;
    protected List<ProcessRelatedPo> relatedList;
    protected boolean noDepartmentHeader;
    protected boolean skipped;
    protected boolean started;

    protected boolean startEvent;

    protected InstanceSnapshotDTO instanceSnapshotDTO;

    public DetailAndProcessInstanceDTO execute(ApprovalPo approvalPo, List<ProcessRelatedPo> processRelatedPoList, ProcessDetailPo before, ApprovalDTO approvalDTO, String checkField, boolean skipped, boolean startEvent) {

        this.approvalPo = approvalPo;
        this.processRelatedPoList = processRelatedPoList;
        this.before = before;
        this.approvalDTO = approvalDTO;
        this.checkField = checkField;
        this.relatedList = new ArrayList<>();
        this.skipped = skipped;
        this.started = true;
        this.noDepartmentHeader = false;
        this.startEvent = startEvent;

        if (!startEvent) {
            ApprovalSnapshotPo approvalSnapshot = approvalSnapshotPoService.getByApprovalId(approvalPo.getApprovalId());
            instanceSnapshotDTO = JSONObject.parseObject(approvalSnapshot.getRelation(), InstanceSnapshotDTO.class);
        }

        boolean match = processBefore();
        // 检查是否还有后继节点, 没有后继节点不进行数据产生

        if (match) {
            // 最后的节点
            if (!hasNext()) {
                finish();
                sendNotify();
                sendFinishMessage();
                return null;
            }

            // 未到最后的节点, 先产生数据, 再回调
            DetailAndProcessInstanceDTO processInstance = generateForCurrent();
            //ApprovalTemplatePo templatePo = approvalTemplateService.getById(approvalPo.getApprovalTemplateId());
            TemplateConfigPo config = templateConfigService.getByTemplateId(approvalPo.getApprovalTemplateId(), approvalPo.getVersion());
            Tuple2<Long, Boolean> tuple = skipped(config, processInstance);
            Long first = tuple.getFirst();
            Boolean second = tuple.getSecond();
            if (second) {
                processSkipped(first, config);
                // 记录该事件, 等全部完成落库以后一个个去发送
                sendNotify();
                return processInstance;
            }

            if (noDepartmentHeader) {
                // reset
                noDepartmentHeader = false;
                sendNotifyMessage();
                return processInstance;
            }

            // 记录该事件, 等全部完成落库以后一个个去发送
            sendNotify();
            // 发送待办消息
            sendNotifyMessage();
        }
        return null;
    }

    public abstract DetailAndProcessInstanceDTO getDetailAndProcessInstances();
    public abstract boolean processBefore();
    public abstract DetailAndProcessInstanceDTO generateForCurrent();

    public void sendNotify() {
        // 是否结束取决于获取状态
        boolean finishFlag = getCurrentStatus();

        // 事件驱动, 保证此次回调的参数信息
        ApprovalCallBack approvalCallBack = eventPublisherBiz.generateEvent(approvalPo);
        approvalCallBack.setSkipped(skipped);
        approvalCallBack.setRemark(approvalDTO.getParam().getRemark());
        approvalCallBack.setApprovalFinished(finishFlag);
        approvalCallBack.setStart(started);


        if (started) {
            approvalCallBack.setEventType(EventTypeEnums.CREATE.getCode());
        }
        if (finishFlag) {
            approvalCallBack.setEventType(EventTypeEnums.FINISH.getCode());
        }

        if (!relatedList.isEmpty()) {
            DetailAndProcessInstanceDTO detailAndProcessInstances = getDetailAndProcessInstances();
            ProcessDetailPo processDetail = detailAndProcessInstances.getProcessDetail();
            if (processDetail.isCounterSign()) {
                approvalCallBack.setLinkType(LinkedTypeEnums.SERIAL.getCode());
            }
            relatedNotEmpty(approvalCallBack);
        } else {
            relatedEmpty(approvalCallBack);
        }

        TriggerCallbackEventData callbackEvent = new TriggerCallbackEventData(approvalCallBack, approvalPo, UserContextHolder.getToken());
        ApprovalEventContext.addEvent(callbackEvent);
    }

    // 发送待办
    protected void sendNotifyMessage() {
        ApprovalTemplatePo templatePo = approvalTemplateService.getById(approvalPo.getApprovalTemplateId());
        TemplateConfigPo config = templateConfigService.getByTemplateId(approvalPo.getApprovalTemplateId(), approvalPo.getVersion());
        // 全局参数是否需要发送
        Boolean approvalNotify = config.getApprovalNotify();
        // 子节点上的模板
        Long processId;

        ProcessDetailPo processDetail = detailAndProcessInstance.getProcessDetail();

        if (Objects.isNull((processDetail.getGroupId()))) {
            processId = processDetail.getNextProcessId();
        } else {
            List<ProcessRelatedPo> relation;
            if (!startEvent) {
                relation = approvalSnapshotDomainService.getRelation(approvalPo.getApprovalId(), null, processDetail);
            } else {
                relation = processRelatedService.listWithGroup(approvalPo.getApprovalTemplateId(), approvalPo.getVersion(), processDetail.getGroupId());
            }
            if(CollectionUtils.isEmpty(relation)){
                return;
            }else{
                processId = relation.get(0).getProcessAfterId();
            }

        }

        List<ProcessNodeNotifyConfig> nodeNotifyConfigList = processNodeNotifyConfigService.listWithProcessId(processId, ApprovalMessageTypeEnum.APPROVAL_NOTIFY);

        if (Boolean.FALSE.equals(approvalNotify) && CollectionUtils.isEmpty(nodeNotifyConfigList)) {
            return;
        }

        // 找到所有的messageKey, 如果节点中有对应的参数, 优先使用子节点的
        for (ProcessNodeNotifyConfig processNodeNotifyConfig : nodeNotifyConfigList) {
            // 检查下是否使用默认的模板
            //if (!ApprovalMessageTypeEnum.defaultValue(processNodeNotifyConfig.getMessageKey())) {}
            // 节点有对应的参数, 并且已经发送, 父节点无需再进行发送
            MessageCenterHelper.send(processNodeNotifyConfig.getMessageKey(), templatePo, approvalPo,
                    detailAndProcessInstance.getProcessInstanceList().stream().map(ProcessInstanceApprovePo::getUserId).collect(Collectors.toList()),
                    config, null);
            approvalNotify = Boolean.FALSE;

        }
        // 全局审批消息
        if  (Boolean.TRUE.equals(approvalNotify)) {
            //发送默认消息模板-审批通知
            MessageCenterHelper.sendDefault(ApprovalMessageTypeEnum.APPROVAL_NOTIFY, templatePo, approvalPo,
                    detailAndProcessInstance.getProcessInstanceList().stream().map(ProcessInstanceApprovePo::getUserId).collect(Collectors.toList()),
                    config, null);
        }
    }

    protected void sendFinishMessage() {
        ApprovalTemplatePo templatePo = approvalTemplateService.getById(approvalPo.getApprovalTemplateId());
        TemplateConfigPo config = templateConfigService.getByTemplateId(approvalPo.getApprovalTemplateId(), approvalPo.getVersion());

        // 全局参数是否需要发送
        Boolean passNotify = config.getPassNotify();

        if (Objects.nonNull(before)) {
            // 子节点上的模板
            Long processId = null;
            if (Objects.isNull(before.getGroupId())) {
                processId = before.getNextProcessId();
            } else {
                List<ProcessRelatedPo> relation;
                if (!startEvent) {
                    relation = approvalSnapshotDomainService.getRelation(approvalPo.getApprovalId(), null, before);
                } else {
                    relation = processRelatedService.listWithGroup(approvalPo.getApprovalTemplateId(), approvalPo.getVersion(), before.getGroupId());
                }
                if (!CollectionUtils.isEmpty(relation)) {
                    processId = relation.get(0).getProcessAfterId();
                }
            }

            List<ProcessNodeNotifyConfig> nodeNotifyConfigList = processNodeNotifyConfigService.listWithProcessId(processId, ApprovalMessageTypeEnum.APPROVAL_PASS);
            if (Boolean.FALSE.equals(passNotify) && CollectionUtils.isEmpty(nodeNotifyConfigList)) {
                return;
            }
            // 找到所有的messageKey, 如果节点中有对应的参数, 优先使用子节点的
            for (ProcessNodeNotifyConfig processNodeNotifyConfig : nodeNotifyConfigList) {
                // 检查下是否使用默认的模板
                //if (!ApprovalMessageTypeEnum.defaultValue(processNodeNotifyConfig.getMessageKey())) {}
                // 节点有对应的参数, 并且已经发送, 父节点无需再进行发送
                MessageCenterHelper.send(processNodeNotifyConfig.getMessageKey(), templatePo, approvalPo, Arrays.asList(approvalPo.getCreateBy()), config, null);
                passNotify = Boolean.FALSE;
            }
        }

        // 全局审批消息
        if  (Boolean.TRUE.equals(passNotify)) {
            //发送默认消息模板-审批通过通知
            MessageCenterHelper.sendDefault(ApprovalMessageTypeEnum.APPROVAL_PASS, templatePo, approvalPo, Arrays.asList(approvalPo.getCreateBy()), config, null);
        }
    }

    public void finish() {
        approvalPo.setStatus(ProcessEnums.FINISH.getCode());
        approvalService.updateById(approvalPo);
    }

    public Tuple2<Long, Boolean> skipped(TemplateConfigPo config, DetailAndProcessInstanceDTO processInstance) {
        // 判断是否有对应的设置, 如果设置不跳过. 直接返回false.
        if (!config.canSkip()) {
            return new Tuple2<>(null, false);
        }
        // 刚开始发起.
        ProcessDetailPo processDetail = this.detailAndProcessInstance.getProcessDetail();

        // 首先判断下一个参数是否有校验条件.
        List<ProcessRelatedPo> relatedPoList;

        if (processDetail.isSpecialNode()) {
            // 发起的时候直接取关联表
            if (startEvent) {
                relatedPoList = processRelatedService.listWithGroup(approvalPo.getApprovalTemplateId(), approvalPo.getVersion(), processDetail.getGroupId());
            } else {
                relatedPoList = approvalSnapshotDomainService.getWithGroup(approvalPo.getApprovalId(), processDetail.getProcessId(), processDetail.getGroupId());
            }
        } else {
            if (startEvent) {
                relatedPoList = processRelatedService.listProcessRelatedAfterProcessId(approvalPo.getApprovalTemplateId(), approvalPo.getVersion(), processDetail.getProcessId());
            } else {
                relatedPoList = approvalSnapshotDomainService.getWithGroup(approvalPo.getApprovalId(), processDetail.getProcessId(), processDetail.getGroupId());
            }
        }

        // 有参数必填的时候也不能跳过
        List<Long> processList = relatedPoList.stream().map(ProcessRelatedPo::getProcessAfterId).collect(Collectors.toList());
        List<ProcessFormNodeRelation> processFormNodeRelations = processFormNodeRelationService.listRequiredNodeAttributes(approvalPo.getApprovalTemplateId(), processList, approvalPo.getVersion());

        if (!CollectionUtils.isEmpty(processFormNodeRelations)) {
            return new Tuple2<>(null, false);
        }

        // 判断是否设计到会签的情况, 会签的情况不能进行跳过
        boolean typeMatch = relatedPoList.stream().allMatch(e -> LinkedTypeEnums.SERIAL.getCode().equals(e.getType()));
        boolean linkedTypeMatch = relatedPoList.stream().allMatch(e -> LinkedTypeEnums.SERIAL.getCode().equals(e.getLinkType()));
        List<ProcessInstanceApprovePo> processInstanceList = this.detailAndProcessInstance.getProcessInstanceList();

        if (typeMatch || linkedTypeMatch) {
            // TODO  会签只有一人的时候 processInstanceList.stream().allMatch(e -> Objects.equals(e.getUserId(), approvalPo.getCreateBy()));
            return new Tuple2<>(null, false);
        }
        return skippedAndReturn(config, before, approvalPo, processInstance.getProcessDetail(), relatedPoList, processInstanceList);
    }

    public boolean hasNext() {
        boolean last = processRelatedPoList.isEmpty();
        if (last || approvalDTO.isForced()) {
            return false;
        }

        // 判断是否有分组参数.
        ProcessRelatedPo processRelatedPo = processRelatedPoList.get(0);
        if (processRelatedPoList.size() > 1) {
            Map<Long, List<ProcessRelatedPo>> groupMap = processRelatedPoList.stream().collect(Collectors.groupingBy(ProcessRelatedPo::getGroupId));
            // 说明有条件分支
            if (groupMap.size() > 1) {
                List<Long> idList = processRelatedPoList.stream().map(BaseEntity::getId).collect(Collectors.toList());
                Map<Long, List<ProcessRelatedAttribute>> relatedMap = processRelatedAttributeService.listByRelatedId(idList).stream().collect(Collectors.groupingBy(ProcessRelatedAttribute::getRelatedId));

                for (Map.Entry<Long, List<ProcessRelatedPo>> entry : groupMap.entrySet()) {
                    ProcessRelatedPo related = entry.getValue().get(0);
                    List<ProcessRelatedAttribute> processRelatedAttributeList = relatedMap.getOrDefault(related.getId(), Collections.emptyList());
                    JSONObject jsonObject = CalculateUtil.checkField(processRelatedAttributeList, checkField);
                    boolean match = CalculateUtil.match(processRelatedAttributeList, jsonObject);
                    if (match) {
                        processRelatedPo = related;
                        break;
                    }
                }
            }
        }
        Long processAfterId = processRelatedPo.getProcessAfterId();
        ProcessPo processPo = null;
        if (!startEvent) {
            processPo = instanceSnapshotDTO.findByProcessId(processAfterId);
        } else {
            processPo = processService.getById(processAfterId);
        }
        return !ProcessUtil.last(processPo.getAssociateGroupId());
    }

    public void processSkipped(Long userId, TemplateConfigPo config) {
        ProcessDetailPo processDetail = this.detailAndProcessInstance.getProcessDetail();
        processDetail.skippedPaas();
        processDetailService.updateById(processDetail);
        processInstanceApproveService.updateApprovalAlone(approvalPo.getApprovalId(), InstanceEnums.PASS.getCode(), "系统自动执行, 原因: 与历史节点审批人相同", userId,config);
    }

    protected boolean updateBefore() {

        // 表示为创建时候的数据. 直接不处理
        if (Objects.isNull(before)) {
            return true;
        }
        started = false;

        // 上一个生成的数据为会签
        if (before.isCounterSign()) {
            boolean finish = counterSign();
            if (!finish) {
                // 标识此次为会签操作
                CounterSignContext.setValue();
                return false;
            }
        }

        // 或签逻辑
        if (before.isSharedApproval()) {
            // 或签更新逻辑
            updateMultiple();
            return true;
        }
        update();
        return true;
    }

    public void updateMultiple() {
        // 设置备注
        String remark = Objects.nonNull(approvalDTO.getParam()) ? approvalDTO.getParam().getRemark() : null;
        before.agree(remark);
        processDetailService.updateById(before);

        // 查询对应的instance数据
        List<ProcessInstanceApprovePo> processInstanceApproves = processInstanceApproveService.getByDetailAndId(approvalPo.getApprovalId(), before.getId());
        if (!CollectionUtils.isEmpty(processInstanceApproves)) {
            processInstanceApproves.forEach(e -> e.pass(remark));
            processInstanceApproveService.updateApprovalAlone(approvalPo.getApprovalId(), InstanceEnums.PASS.getCode(), approvalDTO.getParam().getRemark());
        }
    }

    public boolean counterSign() {
        // 找到上一个的数据
        List<ProcessInstanceApprovePo> processInstanceApproves = processInstanceApproveService.getByDetailAndId(approvalPo.getApprovalId(), before.getId());
        Optional<ProcessInstanceApprovePo> processOptional = processInstanceApproves.stream().filter(e -> Objects.equals(e.getUserId(), UserContextHolder.getUserVo().getUserId())).findAny();
        if (!processOptional.isPresent()) {
            throw new ApiException(ProcessResultCode.PRIVILEGE_NOT_FOUND);
        }
        ProcessInstanceApprovePo processInstanceApprovePo = processOptional.get();
        // 判断状态
        if (processInstanceApprovePo.finish()) {
            throw new ApiException(ProcessResultCode.APPROVAL_STATUS_CHANGE);
        }
        processInstanceApprovePo.setStatus(InstanceEnums.PASS.getCode());
        processInstanceApprovePo.updateSelf();
        processInstanceApprovePo.setRemark(approvalDTO.getParam().getRemark());
        // 判断所有的都已审批完成.
        processInstanceApproveService.updateById(processInstanceApprovePo);

        // 筛选数据进行更新
        List<ProcessInstanceApprovePo> processInstanceApproveList = processInstanceApproves.stream().filter(e -> !Objects.equals(e.getUserId(), UserContextHolder.getUserVo().getUserId())).collect(Collectors.toList());
        String userId = processInstanceApproveList.stream().map(e -> e.getUserId().toString()).collect(Collectors.joining(","));
        String userName = processInstanceApproveList.stream().map(ProcessInstanceApprovePo::getUserName).collect(Collectors.joining(","));
        approvalPo.setUserId(userId);
        approvalPo.setUserName(userName);
        approvalService.updateById(approvalPo);
        return processInstanceApproves.stream().allMatch(ProcessInstanceApprovePo::finish);
    }

    private void update() {
        // 设置备注
        String remark = Objects.nonNull(approvalDTO.getParam()) ? approvalDTO.getParam().getRemark() : null;
        before.agree(remark);
        processDetailService.updateById(before);

        // 查询对应的instance数据
        List<ProcessInstanceApprovePo> processInstanceApproves = processInstanceApproveService.getByDetailAndId(approvalPo.getApprovalId(), before.getId());
        if (!CollectionUtils.isEmpty(processInstanceApproves)) {
            processInstanceApproves.forEach(e -> e.pass(remark));
            processInstanceApproveService.updateBatchById(processInstanceApproves);
        }
    }

    private void relatedNotEmpty(ApprovalCallBack approvalCallBack) {
        // 拿到所有的节点.
        Set<Long> allNodeIds = new HashSet<>();

        relatedList.forEach(e -> {
            allNodeIds.add(e.getProcessBeforeId());
            allNodeIds.add(e.getProcessAfterId());
        });

        List<Long> processIdList = relatedList.stream().map(ProcessRelatedPo::getProcessBeforeId).distinct().collect(Collectors.toList());

        if (!CollectionUtils.isEmpty(allNodeIds)) {
            Map<Long, ProcessPo> nodeMap = processService.listByIds(allNodeIds).stream().collect(Collectors.toMap(BaseEntity::getId, e -> e));
            // TODO 计算NodeName
            calculateCurrentNode(approvalCallBack, nodeMap, processIdList);
            // TODO 计算下一个NodeName
            List<Long> afterIdList = relatedList.stream().map(ProcessRelatedPo::getProcessAfterId).distinct().collect(Collectors.toList());
            calculateNextNode(approvalCallBack, nodeMap, afterIdList);
            // TODO 抄送信息.
            calculateCarbonCopy(approvalCallBack, processIdList);
        }
    }

    private void relatedEmpty(ApprovalCallBack approvalCallBack) {
        if (Objects.isNull(before)) {
            return;
        }
        // 查询Detail中的最后一条记录
        List<Long> processIdList;
        if (before.isSpecialNode()) {
            List<ProcessRelatedPo> processRelatedList = processRelatedService.listProcessRelatedAfterProcessId(approvalPo.getApprovalTemplateId(), approvalPo.getVersion(), before.getProcessId(),before.getGroupId());
            processIdList = processRelatedList.stream().map(ProcessRelatedPo::getProcessAfterId).collect(Collectors.toList());
        } else {
            processIdList = Collections.singletonList(before.getNextProcessId());
        }

        Map<Long, ProcessPo> nodeMap = processService.listByIds(processIdList).stream().collect(Collectors.toMap(BaseEntity::getId, e -> e));
        calculateCurrentNode(approvalCallBack, nodeMap, processIdList);
        calculateCarbonCopy(approvalCallBack, processIdList);
    }

    private void calculateCurrentNode(ApprovalCallBack approvalCallBack, Map<Long, ProcessPo> nodeMap, List<Long> processIdList) {
        if (!CollectionUtils.isEmpty(processIdList)) {
            String nodeName = processIdList.stream().map(e -> nodeMap.get(e).getProcessTitle()).filter(Objects::nonNull).distinct().collect(Collectors.joining(","));
            if (!StringUtils.isEmpty(nodeName)) {
                approvalCallBack.setNodeName(nodeName);
            }
        }
    }

    private void calculateNextNode(ApprovalCallBack approvalCallBack, Map<Long, ProcessPo> nodeMap, List<Long> processIdList) {
        if (!CollectionUtils.isEmpty(processIdList)) {
            String nodeName = processIdList.stream().map(e -> nodeMap.get(e).getProcessTitle()).filter(Objects::nonNull).distinct().collect(Collectors.joining(","));
            approvalCallBack.setNextNodeName(nodeName);
        }
    }

    private void calculateCarbonCopy(ApprovalCallBack approvalCallBack, List<Long> processIdList) {
        if (!CollectionUtils.isEmpty(processIdList)) {
            Optional<List<ProcessCarbonCopyPo>> processCarbonCopyPo =
                    carbonCopyService.listByProcessId(approvalPo.getApprovalTemplateId(), processIdList);

            // 查看是否有特殊的逻辑, 有特殊的逻辑需要进行特殊处理
            List<ProcessCarbonCopyPo> processCarbonCopyPos = processCarbonCopyPo.orElse(Collections.emptyList());
            if (!CollectionUtils.isEmpty(processCarbonCopyPos)) {
                List<ApprovalCallBack.CarbonCopyDTO> simpleList = processCarbonCopyPos.stream().map(ProcessCarbonCopyPo::toDTO).collect(Collectors.toList());
                List<ProcessCarbonCopyPo> create = processCarbonCopyPos.stream().filter(e -> Objects.equals(e.getType(), CarbonCopyEnum.APPROVAL_CREATE_PERSON.getCode())).collect(Collectors.toList());

                // 创建人
                if (!CollectionUtils.isEmpty(create)) {
                    // 查询
                    ApprovalCallBack.CarbonCopyDTO createCC = ApprovalCallBack.CarbonCopyDTO.builder().userId(approvalPo.getCreateBy())
                            .type(CarbonCopyEnum.NORMAL.getCode()).userName(approvalPo.getCreateName()).build();
                    simpleList.add(createCC);
                }

                // 所有人
                List<ProcessCarbonCopyPo> all = processCarbonCopyPos.stream().filter(e -> Objects.equals(e.getType(), CarbonCopyEnum.ALL.getCode())).collect(Collectors.toList());
                if (!CollectionUtils.isEmpty(all)) {
                    // 查询所有已经产生的实例
                    List<ProcessInstanceApprovePo> processInstances =
                            processInstanceApproveService.listApprovalInstance(Collections.singletonList(approvalPo.getApprovalId()));
                    List<ApprovalCallBack.CarbonCopyDTO> list = processInstances.stream().map(
                                    e -> ApprovalCallBack.CarbonCopyDTO.builder().userId(e.getUserId()).userName(e.getUserName()).build())
                            .collect(Collectors.toList());
                    simpleList.addAll(list);
                }

                List<ApprovalCallBack.CarbonCopyDTO> copyList = simpleList.stream().filter(ApprovalCallBack.CarbonCopyDTO::filter).distinct().collect(Collectors.toList());
                if (!CollectionUtils.isEmpty(copyList)) {
                    approvalCallBack.setCarbonCopyList(copyList);
                }
            }
        }
    }

    protected Tuple2<Long, Boolean> skippedAndReturn(TemplateConfigPo config, ProcessDetailPo before, ApprovalPo approvalPo,
                                       ProcessDetailPo processDetailPo, List<ProcessRelatedPo> relatedPoList,
                                       List<ProcessInstanceApprovePo> processInstanceList) {
        Long nextProcessId = processDetailPo.getNextProcessId();
        Map<Long, ProcessPo> processMap = processService.list().stream().collect(Collectors.toMap(BaseEntity::getId, e -> e));
        ProcessPo processPo = processMap.getOrDefault(nextProcessId, new ProcessPo());


        boolean result = false;
        // 提交人跳过
        if (config.startSkip()/* && Objects.isNull(before)*/) {
            // 需要跳过, 下一个审批节点人员=当前发起人员
            if (!ProcessUtil.counterSign(nextProcessId)) {
                // 取出数据进行判断.
                result = processInstanceList.stream().anyMatch(e -> Objects.equals(e.getUserId(), approvalPo.getCreateBy()));
            }
        }

        if (result) {
            return new Tuple2<>(approvalPo.getCreateBy(), true);
        }

        // 连续跳过
        if (config.continueSkip()) {
            // 说明是发起者
            if (Objects.isNull(before)) {
                // 说明是发起
//                result = processInstanceList.stream().anyMatch(e -> Objects.equals(e.getUserId(), approvalPo.getCreateBy()));
            } else {
                // 找到上次的数据进行比对
                List<UserDTO> currentUserDTO =
                        processInstanceList.stream().map(e -> UserDTO.builder().userId(e.getUserId()).userName(e.getUserName()).build())
                                .collect(Collectors.toList());

                List<ProcessInstanceApprovePo> last =
                        processInstanceApproveService.getByDetailId(approvalPo.getApprovalId(), before.getId());

                List<UserDTO> lastUserDTO =
                        last.stream().map(e -> UserDTO.builder().userId(e.getUserId()).userName(e.getUserName()).build())
                                .collect(Collectors.toList());

                // 判断两个是否相同
                lastUserDTO.removeAll(currentUserDTO);
                result = lastUserDTO.isEmpty();
            }
        }
        if (result) {
            return new Tuple2<>(null, true);
        }

        // 历史任意节点
        if (config.historySkip()) {
            if (Objects.isNull(before)) {
                // 说明是发起
//                result = processInstanceList.stream().anyMatch(e -> Objects.equals(e.getUserId(), approvalPo.getCreateBy()));
            } else {
                // 查找所有的数据进行比对
                List<ProcessInstanceApprovePo> processInstanceApproveList = processInstanceApproveService.listApprovedInstance(approvalPo.getApprovalId());
                // 如果或签节点
                if (ProcessUtil.orSign(nextProcessId)) {
                    List<Long> processIdList = relatedPoList.stream().map(ProcessRelatedPo::getProcessAfterId).distinct().collect(Collectors.toList());
                    result = processInstanceApproveList.stream().anyMatch(e -> processIdList.stream().anyMatch(x -> Objects.equals(String.valueOf(e.getUserId()),
                            processMap.getOrDefault(x, new ProcessPo()).getAssociateGroupId())));
                } else if (processPo.isApproval()) {
                    result = processInstanceApproveList.stream().anyMatch(e -> Objects.equals(approvalPo.getCreateBy(), e.getUserId()));
                } else {
                    result = processInstanceApproveList.stream().anyMatch(e -> Objects.equals(processPo.getAssociateGroupId(), String.valueOf(e.getUserId())));
                }
            }
        }

        return new Tuple2<>(null, result);
    }

    private boolean getCurrentStatus() {
        return approvalPo.isFinish();
    }

    protected DetailAndProcessInstanceDTO generateCurrent() {
        DetailAndProcessInstanceDTO detailAndProcessInstance = getDetailAndProcessInstances();
        this.detailAndProcessInstance = detailAndProcessInstance;
        ProcessDetailPo processDetail = detailAndProcessInstance.getProcessDetail();
        List<ProcessInstanceApprovePo> processInstanceApproveList = detailAndProcessInstance.getProcessInstanceList();

        processDetailService.save(processDetail);
        processInstanceApproveService.saveBatch(processInstanceApproveList);

        List<String> userIdList = new ArrayList<>();
        List<String> userNameList = new ArrayList<>();

        processInstanceApproveList.forEach(e -> {
            userIdList.add(e.getUserId().toString());
            userNameList.add(e.getUserName());
        });

        // 生成approval中的审批用户id和名称
        approvalPo.setUserId(StringUtils.collectionToDelimitedString(userIdList, ","));
        approvalPo.setUserName(StringUtils.collectionToDelimitedString(userNameList, ","));

        approvalService.updateById(approvalPo);
        return detailAndProcessInstance;
    }

    protected ApprovalUserDTO processDepartHead() {
        UserVO userVo = UserContextHolder.getUserVo();

        DepartmentHeadVO department = privilegeClient
                .getDepartmentHead(UserDTO.builder().userId(userVo.getUserId()).build())
                .getObj();
        if (Objects.isNull(department) || Objects.isNull(department.getDepartmentHead())) {
            // 继续下一个
            return null;
        }
        Long userId = department.getDepartmentHead().getUserId();
        String userName = department.getDepartmentHead().getUsername();
        return ApprovalUserDTO.builder().userId(userId).userName(userName).build();
    }

    protected List<ProcessInstanceApprovePo> getUserIdList(List<ProcessRelatedPo> processRelatedPoList, Integer approvalType, Long detailId) {

        List<Long> processIdList = processRelatedPoList.stream().map(ProcessRelatedPo::getProcessAfterId).collect(Collectors.toList());
        Map<Long, ProcessPo> processMap = null;
        if (!startEvent) {
            processMap = instanceSnapshotDTO.listByIds(processIdList).stream().collect(Collectors.toMap(BaseEntity::getId, e -> e));
        } else {
            processMap = processService.listByIds(processIdList).stream().collect(Collectors.toMap(BaseEntity::getId, e -> e));
        }

        // 并行说明有条件分支. 分支条件来进行判断最终拿到一个

        // 将所有的审批人加入到这次审批中
        Map<Long, ProcessPo> finalProcessMap = processMap;
        return processRelatedPoList.stream().map(e -> {
            ProcessPo processPo = finalProcessMap.get(e.getProcessAfterId());
            processPo = transfer(processPo);
            ProcessInstanceApprovePo approvePo = ProcessInstanceApprovePo.of(approvalPo);
            approvePo.setApprovalType(approvalType);
            approvePo.setUserId(Long.valueOf(processPo.getAssociateGroupId()));
            approvePo.setUserName(processPo.getAssociateGroupName());
            approvePo.setApprovalDetailId(detailId);
            return approvePo;
        }).collect(Collectors.toList());
    }


    private ProcessPo transfer(ProcessPo processPo) {
        if (Objects.isNull(processPo)) {
            return null;
        }
        // 自选人
        if (ProcessUtil.optional(processPo.getAssociateGroupId())) {
            Long nextUserId = approvalDTO.getNextUserId();
            String nextUserName = approvalDTO.getNextUserName();
            processPo.setAssociateGroupId(nextUserId.toString());
            processPo.setAssociateGroupName(nextUserName);
        }
        // 创建人
        if (processPo.isApproval()) {
            processPo.setAssociateGroupId(approvalPo.getCreateBy().toString());
            processPo.setAssociateGroupName(approvalPo.getCreateName());
        }
        // TODO: 部门负责人
        if (ProcessUtil.department(processPo.getAssociateGroupId())) {

        }
        return processPo;

    }

    // 没部门的时候负责人直接跳过
    protected DetailAndProcessInstanceDTO noDepartment() {

        ProcessRelatedPo processRelated = processRelatedPoList.get(0);
        ProcessDetailPo processDetailPo = new ProcessDetailPo();
        processDetailPo.setId(UuidUtil.generateId());
        processDetailPo.setProcessId(processRelated.getProcessBeforeId());
        processDetailPo.setNextProcessId(processRelated.getProcessAfterId());
        processDetailPo.setResultType(ProcessResultTypeEnums.PASS.getIndex());
        processDetailPo.setApprovalTemplateId(approvalPo.getApprovalTemplateId());
        processDetailPo.setParentId(approvalPo.getApprovalId());
        processDetailPo.setCreateBy(approvalPo.getCreateBy());
        processDetailPo.setCreateName(approvalPo.getCreateName());

        // instance 表增加数据
        ProcessInstanceApprovePo processInstanceApprovePo = ProcessInstanceApprovePo.of(approvalPo);
        processInstanceApprovePo.setStatus(BooleanEnum.Y.getCode());
        processInstanceApprovePo.setApprovalDetailId(processDetailPo.getId());

        processInstanceApprovePo.setUserId(-1L);
        processInstanceApprovePo.setUserName("无领导审批,跳过该审批");

        processInstanceApprovePo.setIsSkip(Boolean.TRUE);
        processInstanceApprovePo.setCreateBy(UserContextHolder.getUserVo().getUserId());
        processInstanceApprovePo.setCreateName(UserContextHolder.getUserVo().getRealName());

        return DetailAndProcessInstanceDTO.builder().processDetail(processDetailPo)
                .processInstanceList(Collections.singletonList(processInstanceApprovePo)).build();
    }

    protected List<ProcessInstanceApprovePo> department(Long userId, String userName, Long detailId) {
        ProcessInstanceApprovePo processInstance = ProcessInstanceApprovePo.of(approvalPo);
        processInstance.setType(ProcessApprovalEnums.DEPARTMENT.getCode());
        processInstance.setUserId(userId);
        processInstance.setApprovalDetailId(detailId);
        processInstance.setUserName(userName);
        return Collections.singletonList(processInstance);
    }

    protected List<ProcessInstanceApprovePo> optional(Long userId, String userName, Long detailId) {
        List<ProcessInstanceApprovePo> processInstances = department(userId, userName, detailId);
        processInstances.forEach(e -> e.setType(ProcessApprovalEnums.INDIVIDUAL.getCode()));
        return processInstances;
    }

    protected List<ProcessInstanceApprovePo> individual(Long userId, String userName, Long detailId) {
        return optional(userId, userName, detailId);
    }
}
